import React from 'react';
import PropTypes from 'prop-types';
import {withStyles} from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import TableFooter from '@material-ui/core/TableFooter';
import TablePagination from '@material-ui/core/TablePagination';
import TablePaginationAction from './TablePaginationAction';
import CheckBox from '@material-ui/core/Checkbox';
import Tooltip from '@material-ui/core/Tooltip';
import TableSortLabel from '@material-ui/core/TableSortLabel';
import DeleteIcon from '@material-ui/icons/Delete';
import EditIcon from '@material-ui/icons/Edit';
import IconButton from '@material-ui/core/IconButton';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContentText from '@material-ui/core/DialogContentText';
import NormalTextField from '../../TextField/NormalTextField';
import DialogActions from '@material-ui/core/DialogActions'
import EnhancedTableToolbar from './EnhancedTableToolbar';
import SearchText from './SearchText';
import Grid from '@material-ui/core/Grid';
import TimeTextField from '../../TextField/TimeTextField';
import DateTextField from '../../TextField/DateTextField'

/**
 * custom style you can use
 * @param theme
 */
const styles = theme => ({
    tableContainer: {overflow: 'auto', position: 'relative'},
    //表格样式
    table: {borderTop: '#e0e0e0 1px solid', tableLayout: 'fixed'},
    //表头样式
    thead: {borderLeft: '#e0e0e0 1px solid', borderRight: '#e0e0e0 1px solid'},
    //表体样式
    tbody: {borderLeft: '#e0e0e0 1px solid', borderRight: '#e0e0e0 1px solid'},

    //表头行样式
    headRow: {},
    //表头列样式
    headCell: {textAlign: "center", wordBreak: 'keep-all', padding: '0', '&:last-child': {paddingRight: "0px"}},
    //表体行样式
    bodyRow: {
        '&:nth-of-type(odd)': {
            backgroundColor: theme.palette.background.default,
        },
        '&:nth-of-type(even)': {},
        '&$bodyRowSelected': {
            backgroundColor: "rgba(0, 0, 0, 0.07)",
        },
    },
    //表体列样式
    bodyCell: {textAlign: 'center', '&:last-child': {paddingRight: "0px"}, wordBreak: 'keep-all', padding: '0'},
    bodyRowSelected: {},
});

function desc(a, b, orderBy) {
    if (b[orderBy] < a[orderBy]) {
        return -1;
    }
    if (b[orderBy] > a[orderBy]) {
        return 1;
    }
    return 0;
}

function stableSort(array, cmp) {

    const stabilizedThis = array.map((el, index) => [el, index]);
    stabilizedThis.sort((a, b) => {
        const order = cmp(a[0], b[0]);
        if (order !== 0) return order;
        return a[1] - b[1];
    });
    return stabilizedThis.map(el => el[0]);
}

function filterRow(array, filterTexts, rowNames) {
    return array.filter(function (elem) {
        for (let i = 0; i < rowNames.length; i++) {
            if (filterTexts[rowNames[i]] !== "" && elem[rowNames[i]].toString().toLowerCase().indexOf(filterTexts[rowNames[i]].toLowerCase()) < 0) {
                return false
            }
        }
        return true
    })
}

function getSorting(order, orderBy) {
    return order === 'desc' ? (a, b) => desc(a, b, orderBy) : (a, b) => -desc(a, b, orderBy);
}

class DataEditingTable extends React.Component {

    state = {
        order: 'asc',
        orderBy: -1,
        sortActive: false,
        checked: [],
        sortActiveIndex: 0,
        rows: this.props.rows,
        rowsPerPage: this.props.rowsPerPage,
        page: this.props.page,
        addOpen: false,
        addRow: {},
        editOpen: false,
        editRow: {},
        deleteOpen: false,
        deleteRow: {},
        filterTexts: {},
        deleteAllOpen: false,
        rowNames: this.props.rowNames,
        columnNames: this.props.columnNames,
    }

    componentWillMount() {
        const {rowNames, addRow} = this.state;

        let filterTexts = {}
        rowNames.forEach(function (elem, index) {
            filterTexts[elem] = "";
            addRow[elem] = "";
        })
        this.setState({rows: this.createDataWithTableId(this.props.rows), filterTexts, addRow});
    }

    /**
     * the tableId is used for support checked actions
     * Do not use tableId as an attribute, especially when an object has an ID
     */
    createDataWithTableId = (rows) => {
        let count = 0
        let newRows = rows.map(data => {
            data.tableId = count;
            count += 1;
            return data;
        })
        return newRows;
    };

    handleChangePage = (event, page) => {
        this.setState({page});
    };

    handleChangeRowsPerPage = event => {
        this.setState({rowsPerPage: parseInt(event.target.value)});
    };

    /**
     * 排序
     * @param event
     * @param index
     */
    handleSortActive = (event, index) => {
        this.setState({
            sortActiveIndex: index,
            sortActive: true,
            order: this.state.order === "desc" ? "asc" : "desc",
            orderBy: this.props.rowNames[index]
        });
    };

    handleCheckedRow = (event, id) => {
        const {checked} = this.state;
        const checkedIndex = checked.indexOf(id);
        let newChecked = [];

        if (checkedIndex === -1) {
            newChecked = newChecked.concat(checked, id);
        } else if (checkedIndex === 0) {
            newChecked = newChecked.concat(checked.slice(1));
        } else if (checkedIndex === checked.length - 1) {
            newChecked = newChecked.concat(checked.slice(0, -1));
        } else if (checkedIndex > 0) {
            newChecked = newChecked.concat(
                checked.slice(0, checkedIndex),
                checked.slice(checkedIndex + 1),
            );
        }
        this.setState({checked: newChecked});
    }

    handleSelectAllClick = event => {
        if (event.target.checked) {
            this.setState(state => ({checked: state.rows.map(n => n.tableId)}));
            return;
        }
        this.setState({checked: []});
    };

    handleAddRowChange = (value, index) => {
        let {addRow, rowNames} = this.state
        addRow[rowNames[index]] = value
        this.setState({addRow})
    }

    handleAddOpen = () => {
        this.setState({addOpen: true})
    }

    handleAddClose = () => {
        this.setState({addOpen: false})
    }

    handleAddDataClose = () => {
        let addRow = this.state.addRow
        const addFunc = this.props.addFunc
        if (typeof addFunc === "function") {
            addFunc(addRow)
        }
        this.setState({addOpen: false})
    }

    handleEditOpen = (row) => {
        const editRow = Object.assign({}, row)
        this.setState({editOpen: true, editRow})
    }

    handleEditDataClose = () => {
        let editRow = this.state.editRow
        const editFunc = this.props.editFunc
        if (typeof editFunc === "function") {
            editFunc(editRow)
        }
        this.setState({editOpen: false})
    }

    handleEditClose = () => {
        this.setState({editOpen: false})
    }

    handleEditRow = (value, index) => {
        let {editRow, rowNames} = this.state
        editRow[rowNames[index]] = value
        this.setState({editRow})
    }

    handleDeleteOpen = (row) => {
        this.setState({deleteOpen: true, deleteRow: row})
    }

    handelDeleteClose = () => {
        this.setState({deleteOpen: false})
    }

    handelDeleteDataClose = () => {
        let deleteRow = this.state.deleteRow
        const deleteFunc = this.props.deleteFunc
        if (typeof deleteFunc === "function") {
            deleteFunc(deleteRow)
        }
        this.setState({deleteOpen: false})
    }

    handleDeleteAllOpen = (row) => {
        this.setState({deleteAllOpen: true})
    }

    handelDeleteAllClose = () => {
        this.setState({deleteAllOpen: false})
    }

    handleDeleteAllDataClose = () => {

        let deleteArray = []
        const {rows, checked} = this.state

        checked.forEach(function (index) {
            deleteArray.push(rows[index])
        })

        this.props.batchDeleteFunc(deleteArray)
        this.setState({deleteAllOpen: false})
    }

    handleFilterTextChange = (event, rowName) => {
        let filterTexts = this.state.filterTexts
        filterTexts[rowName] = event.target.value
        this.setState({filterTexts})
    }

    handleColumnNames = (rowNames, columnNames) => {
        this.setState({rowNames, columnNames})
    }

    isChecked = id => this.state.checked.indexOf(id) !== -1;

    renderRowOperation = (row) => {
        const {classes} = this.props
        return (
            <TableCell className={classes.bodyCell}>
                <IconButton onClick={event => (this.handleEditOpen(row))}><EditIcon/></IconButton>
                <IconButton><DeleteIcon onClick={event => (this.handleDeleteOpen(row))}/></IconButton>
            </TableCell>
        )
    }

    renderHeaderOperation = () => {
        const {classes} = this.props
        return (
            <TableCell className={classes.headCell}>
                <Button onClick={this.handleAddOpen} className={classes.headAdd}>添加</Button>
            </TableCell>
        )
    }

    renderCheckBox = () => {
        const {classes, hover, dateColumn, timeColumn, title, searchFunc} = this.props;

        const {
            columnNames, rowNames, rows, rowsPerPage, page, checked, sortActive,
            sortActiveIndex, order, orderBy, filterTexts
        } = this.state;


        const realRows = stableSort(filterRow(rows, filterTexts, rowNames), getSorting(order, orderBy))
            .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
        return (
            <Grid container className={classes.tableContainer}>
                <Grid item xs={12}>
                    <EnhancedTableToolbar numSelected={checked.length}
                                          title={title}
                                          rowNames={this.props.rowNames}
                                          batchDeleteFunc={this.handleDeleteAllOpen}
                                          columnNames={this.props.columnNames}
                                          handleColumnNames={this.handleColumnNames}
                                          handleFilterTextChange={this.handleFilterTextChange}
                                          filterTexts={filterTexts}/>
                </Grid>
                <Grid item xs={12}>
                    <Table className={classes.table}>
                        <TableHead className={classes.thead}>
                            <TableRow className={classes.headRow}>
                                <TableCell padding="checkbox">
                                    <CheckBox indeterminate={checked.length > 0 && checked.length < rows.length}
                                              checked={checked.length === rows.length}
                                              onChange={this.handleSelectAllClick}>
                                    </CheckBox>
                                </TableCell>
                                {
                                    columnNames.map((cell, index) => (
                                        <TableCell key={index}
                                                   className={classes.headCell}
                                                   sortDirection={'asc'}
                                        >
                                            <Tooltip
                                                title={sortActive && sortActiveIndex === index ? order === "desc" ? "降序" : "升序" : "排序"}
                                                placement={'bottom-end'}
                                                enterDelay={300}
                                            >
                                                <TableSortLabel direction={order}
                                                                active={sortActive && sortActiveIndex === index}
                                                                onClick={(event) => this.handleSortActive(event, index)}>{cell}</TableSortLabel>
                                            </Tooltip>
                                        </TableCell>
                                    ))
                                }
                                {this.renderHeaderOperation()}
                            </TableRow>
                        </TableHead>
                        <TableBody className={classes.tbody}>
                            <SearchText rowNames={rowNames}
                                        dateColumn={dateColumn}
                                        timeColumn={timeColumn}
                                        searchFunc={searchFunc}
                            ></SearchText>
                            {
                                realRows.map((row, index) => {
                                    const isChecked = this.isChecked(row.tableId);
                                    return (
                                        <TableRow key={index}
                                                  classes={{root: classes.bodyRow, selected: classes.bodyRowSelected}}
                                                  hover={hover}
                                                  selected={isChecked}
                                        >
                                            <TableCell padding="checkbox"
                                                       onClick={(event) => this.handleCheckedRow(event, row.tableId)}>
                                                <CheckBox checked={isChecked}/>
                                            </TableCell>
                                            {
                                                rowNames.map((rowName, index) => (
                                                    <TableCell key={index}
                                                               className={classes.bodyCell}>
                                                        {row[rowName]}
                                                    </TableCell>

                                                ))
                                            }

                                            {this.renderRowOperation(row)}
                                        </TableRow>
                                    )
                                })
                            }
                        </TableBody>
                        <TableFooter>
                            <TableRow>
                                <TablePagination
                                    rowsPerPageOptions={[5, 10, 15, 20, 25, 30]}
                                    colSpan={1}
                                    count={rows.length}
                                    rowsPerPage={rowsPerPage}
                                    page={page}
                                    labelDisplayedRows={({from, to, count}) => `当前显示 ${from} - ${to} 条 总共${count}条`}
                                    labelRowsPerPage={"显示行数"}
                                    onChangePage={this.handleChangePage}
                                    onChangeRowsPerPage={this.handleChangeRowsPerPage}
                                    ActionsComponent={TablePaginationAction}
                                />
                            </TableRow>
                        </TableFooter>
                    </Table>
                </Grid>
            </Grid>
        )
    }

    renderAddDialog = () => {
        const {addRow} = this.state;
        const {rowNames, columnNames, dateColumn, dateFormat, timeFormat, timeColumn} = this.props
        return (
            <Dialog
                open={this.state.addOpen}
                onClose={this.handleAddClose}
                aria-labelledby="form-dialog-title"
            >
                <DialogTitle id="form-dialog-title">添加信息</DialogTitle>
                <DialogContent>
                    <DialogContentText>
                        请输入要添加的记录
                    </DialogContentText>
                    {
                        columnNames.map((cell, index) => (
                            dateColumn.indexOf(index + 1) !== -1 ?
                                <DateTextField
                                    dateFormat={dateFormat}
                                    key={index}
                                    margin="dense"
                                    label={cell}
                                    type="text"
                                    fullWidth
                                    autoComplete="off"
                                    value={addRow[rowNames[index]]}
                                    parameters={[index]}
                                    onChange={this.handleAddRowChange}
                                /> :
                                timeColumn.indexOf(index + 1) !== -1 ?
                                <TimeTextField
                                    timeFormat={timeFormat}
                                    key={index}
                                    margin="dense"
                                    label={cell}
                                    type="text"
                                    fullWidth
                                    autoComplete="off"
                                    value={addRow[rowNames[index]]}
                                    parameters={[index]}
                                    onChange={this.handleAddRowChange}
                                /> :
                                <NormalTextField
                                    key={index}
                                    margin="dense"
                                    label={cell}
                                    type="text"
                                    fullWidth
                                    autoComplete="off"
                                    value={addRow[rowNames[index]]}
                                    parameters={[index]}
                                    onChange={this.handleAddRowChange}
                                />
                        ))
                    }
                </DialogContent>
                <DialogActions>
                    <Button onClick={this.handleAddClose} color="primary">
                        取消
                    </Button>
                    <Button onClick={this.handleAddDataClose} color="primary">
                        添加
                    </Button>
                </DialogActions>
            </Dialog>
        );
    }

    renderEditDialog = () => {
        const {editRow} = this.state
        const {columnNames, rowNames, dateColumn, dateFormat, timeFormat, timeColumn} = this.props;
        return (
            editRow ? <Dialog
                open={this.state.editOpen}
                onClose={this.handleEditClose}
                aria-labelledby="form-dialog-title"
            >
                <DialogTitle id="form-dialog-title">修改信息</DialogTitle>
                <DialogContent>
                    <DialogContentText>
                        请输入修改的信息
                    </DialogContentText>
                    {
                        columnNames.map((cell, index) => (
                            dateColumn.indexOf(index + 1) !== -1 ?
                                <DateTextField
                                    dateFormat={dateFormat}
                                    key={index}
                                    margin="dense"
                                    label={cell}
                                    type="text"
                                    fullWidth
                                    autoComplete="off"
                                    value={editRow[rowNames[index]]}
                                    parameters={[index]}
                                    onChange={this.handleEditRow}
                                /> :
                                timeColumn.indexOf(index + 1) !== -1 ?
                                    <TimeTextField
                                        timeFormat={timeFormat}
                                        key={index}
                                        margin="dense"
                                        label={cell}
                                        type="text"
                                        fullWidth
                                        autoComplete="off"
                                        value={editRow[rowNames[index]]}
                                        parameters={[index]}
                                        onChange={this.handleEditRow}
                                    /> :
                                    <NormalTextField
                                        key={index}
                                        margin="dense"
                                        label={cell}
                                        type="text"
                                        fullWidth
                                        autoComplete="off"
                                        value={editRow[rowNames[index]]}
                                        parameters={[index]}
                                        onChange={this.handleEditRow}
                                    />
                        ))
                    }
                </DialogContent>
                <DialogActions>
                    <Button onClick={this.handleEditClose} color="primary">
                        取消
                    </Button>
                    <Button onClick={this.handleEditDataClose} color="primary">
                        确定
                    </Button>
                </DialogActions>
            </Dialog> : ""
        );
    }

    renderDeleteDialog = () => {
        const {columnNames, rowNames} = this.props
        const {deleteRow} = this.state;
        return (
            deleteRow ? <Dialog
                open={this.state.deleteOpen}
                onClose={this.handelDeleteClose}
                aria-labelledby="form-dialog-title"
            >
                <DialogTitle id="form-dialog-title">删除信息</DialogTitle>
                <DialogContent>
                    <DialogContentText>
                        确定要删除这条信息吗
                    </DialogContentText>
                    <Table>
                        <TableHead>
                            <TableRow>
                                {
                                    columnNames.map((cell, index) => (
                                        <TableCell key={index}>{cell}</TableCell>
                                    ))
                                }
                            </TableRow>
                        </TableHead>
                        <TableBody>
                            <TableRow>
                                {
                                    columnNames.map((cell, index) => (
                                        <TableCell key={index}>{deleteRow[rowNames[index]]}</TableCell>
                                    ))
                                }
                            </TableRow>
                        </TableBody>
                    </Table>
                </DialogContent>
                <DialogActions>
                    <Button onClick={this.handelDeleteClose} color="primary">
                        取消
                    </Button>
                    <Button onClick={this.handelDeleteDataClose} color="primary">
                        确定
                    </Button>
                </DialogActions>
            </Dialog> : ""
        )
    }

    renderDeleteAllDialog = () => {
        const {deleteAllOpen, checked} = this.state;
        return (
            <Dialog
                open={deleteAllOpen}
                onClose={this.handelDeleteAllClose}
                aria-labelledby="form-dialog-title"
            >
                <DialogTitle id="form-dialog-title"><DeleteIcon></DeleteIcon></DialogTitle>
                <DialogContent>
                    <DialogContentText>
                        {`确定要删除${checked.length}条信息吗`}
                    </DialogContentText>
                </DialogContent>
                <DialogActions>
                    <Button onClick={this.handelDeleteAllClose} color="primary">
                        取消
                    </Button>
                    <Button onClick={this.handleDeleteAllDataClose} color="primary">
                        确定
                    </Button>
                </DialogActions>
            </Dialog>
        )
    }

    render() {
        return (
            <Grid container>
                {this.renderCheckBox()}
                {this.renderAddDialog()}
                {this.renderEditDialog()}
                {this.renderDeleteDialog()}
                {this.renderDeleteAllDialog()}
            </Grid>
        )
    }
}
DataEditingTable.defaultProps = {
    dateFormat: 'yyyy-MM-dd'
}
DataEditingTable.propTypes = {
    classes: PropTypes.object.isRequired,
    columnNames: PropTypes.array.isRequired, //每一列的名字
    rowNames: PropTypes.array.isRequired, //每一行的索引值
    rows: PropTypes.array, //行数
    page: PropTypes.number.isRequired,//当前页数
    rowsPerPage: PropTypes.number.isRequired,//每页显示的行数
    hover: PropTypes.bool, //是否有鼠标停留的样式
    hasSort: PropTypes.bool, //是否使用排序功能
    title: PropTypes.string, //表名
    addFunc: PropTypes.func, //添加接口
    editFunc: PropTypes.func, //编辑接口
    deleteFunc: PropTypes.func, //删除接口
    searchFunc: PropTypes.func,//查询接口
    batchDeleteFunc: PropTypes.func, //批量删除接口
    dateColumn: PropTypes.array, //日期列
    timeColumn: PropTypes.array, //时间列
    selectColumn: PropTypes.array,//选择列
    dateFormat: PropTypes.string//日期格式
};

export default withStyles(styles)(DataEditingTable);
